package com.springcloud.commom.aop;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.springcloud.auth.feign.IAuthClient;
import com.springcloud.auth.utils.OauthUtils;
import com.springcloud.commom.annotion.BusinessLog;
import com.springcloud.commom.api.R;
import com.springcloud.commom.constant.CommonConstant;
import com.springcloud.commom.utils.HttpServletUtil;
import com.springcloud.commom.utils.IpAddressUtil;
import com.springcloud.commom.utils.JoinPointUtil;
import com.springcloud.commom.utils.UaUtil;
import com.springcloud.log.entity.SysOpLog;
import com.springcloud.log.enums.LogSuccessStatusEnum;
import com.springcloud.log.feign.ILogClient;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;

/**
 * 业务日志aop切面
 *
 * @author xuyuxiang
 * @date 2020/3/20 11:47
 */

/**
 * 申明是个切面
 */
@Aspect
///**申明是个组件*/
@Component
///**标记定义了优先顺序。*/
@Order(10)
public class BusinessLogAop {

    @Resource
    private IAuthClient authClient;

    @Resource
    private ILogClient logClient;

    /**
     * 日志切入点
     */
    @Pointcut("@annotation(com.springcloud.commom.annotion.BusinessLog)")
    private void getLogPointCut() {
    }

    /**
     * 操作成功返回结果记录日志
     *
     * @author xuyuxiang
     * @date 2020/3/20 11:51
     */
    @AfterReturning(pointcut = "getLogPointCut()", returning = "result")
    public void doAfterReturning(JoinPoint joinPoint, Object result) {
        String account = getAccount();
        if (StringUtils.isBlank(account)) {
            return;
        }

        SysOpLog sysOpLog = getOpLog(joinPoint, result, account, null);

        //调用接口日志
        logClient.saveOpLog(sysOpLog);
    }

    /**
     * 操作发生异常记录日志
     *
     * @author xuyuxiang
     * @date 2020/3/21 11:38
     */
    @AfterThrowing(pointcut = "getLogPointCut()", throwing = "exception")
    public void doAfterThrowing(JoinPoint joinPoint, Exception exception) {
        String account = getAccount();
        if (StringUtils.isBlank(account)) {
            return;
        }

        SysOpLog sysOpLog = getOpLog(joinPoint, null, account, exception);

        //调用接口日志
        logClient.saveOpLog(sysOpLog);
    }

    private String getAccount() {
        String accessToken = OauthUtils.getAccessToken();
        R<Map<String, String>> re = authClient.getAccount(accessToken);

        if (re.getCode() != 200) {
            return "";
        } else {
            Map<String, String> map = re.getData();
            String account = map.get("account");

            return account;
        }
    }

    private SysOpLog getOpLog(JoinPoint joinPoint, Object result, String account, Exception exception) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        BusinessLog businessLog = method.getAnnotation(BusinessLog.class);
        if (ObjectUtil.isNull(account)) {
            account = CommonConstant.UNKNOWN;
        }

        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        String param = JoinPointUtil.getArgsJsonString(joinPoint);
        SysOpLog sysOpLog = new SysOpLog();

        sysOpLog.setName(businessLog.title());
        sysOpLog.setOpType(businessLog.opType().ordinal());
        sysOpLog.setClassName(className);
        sysOpLog.setMethodName(methodName);
        sysOpLog.setParam(param);
        sysOpLog.setOpTime(DateTime.now());
        sysOpLog.setAccount(account);

        if (ObjectUtil.isNull(result)) {
            sysOpLog.setSuccess(LogSuccessStatusEnum.FAIL.getCode());
            sysOpLog.setMessage(Arrays.toString(exception.getStackTrace()));
        } else {
            sysOpLog.setSuccess(LogSuccessStatusEnum.SUCCESS.getCode());
            sysOpLog.setResult(JSON.toJSONString(result));
            sysOpLog.setMessage(LogSuccessStatusEnum.SUCCESS.getMessage());
        }

        HttpServletRequest request = HttpServletUtil.getRequest();
        String ip = IpAddressUtil.getIp(request);
        String browser = UaUtil.getBrowser(request);
        String os = UaUtil.getOs(request);
        String url = request.getRequestURI();
        String reqMethod = request.getMethod();

        sysOpLog.setIp(ip);
        sysOpLog.setBrowser(browser);
        sysOpLog.setOs(os);
        sysOpLog.setUrl(url);
        sysOpLog.setReqMethod(reqMethod);

        return sysOpLog;
    }
}
